/*
 * MySQL Cluster SNMP monitoring subagent
 * Copyright (C) 2011, Steven Ayre <steveayre@gmail.com>
 *
 * Version: MPL 1.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is MySQL Cluster SNMP monitoring subagent
 *
 * The Initial Developer of the Original Code is
 * Steven Ayre <steveayre@gmail.com>
 * Portions created by the Initial Developer are Copyright (C)
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *
 * Steven Ayre <steveayre@gmail.com>
 *
 * ndb_snmpd.c -- Main
 *
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <libdaemon/daemon.h>
#include "ndb_snmpd.h"
#include "common.h"
#include "config.h"
#include "thread.h"
#include "ndb_mgm.h"
#include "subagent.h"

globals_t globals;

static void signal_handler(int sig)
{
	switch(sig) {
		case SIGHUP:
		case SIGINT:
		case SIGTERM:
		case SIGQUIT:
			globals.running = 0;
			break;
		default:
			break;
	}
}

int main(int argc, char *argv[])
{
	thread_t **threads = NULL;
	int num_threads = 0, status = 0, i;

	/* TODO Initial version only runs in foreground while the basic monitoring is developed, later versions will daemonise */

	/* Initialise globals */
	memset(&globals, 0, sizeof(globals));
	globals.running = 1;

	/* Set identification string for the daemon for both syslog and PID file */
	daemon_pid_file_ident = daemon_log_ident = daemon_ident_from_argv0(argv[0]);

	/* Set logging level */
	daemon_set_verbosity(LOG_DEBUG);

	/* Load configuration file */
	if (config_load(DEFAULT_CONFIG_FILE) < 0) {
		daemon_log(LOG_ERR, "Failed to load configuration");
		status = -1;
		goto end;
	}

	/* Install signal handlers */
	if (   (signal(SIGHUP,  signal_handler) == SIG_ERR)
	    || (signal(SIGINT,  signal_handler) == SIG_ERR)
	    || (signal(SIGTERM, signal_handler) == SIG_ERR)
	    || (signal(SIGQUIT, signal_handler) == SIG_ERR)) {
		daemon_perror(LOG_ERR, "signal");
		status = -1;
		goto end;
	}

	/* Allocate enough memory for the threads */
	num_threads = globals.num_clusters + 1;
	if (num_threads <= 1) {
		daemon_log(LOG_ERR, "Specify at least one connectstring at the commandline");
		status = -1;
		goto end;
	}
	if (!(threads = (thread_t**)calloc(num_threads, sizeof(thread_t*)))) {
		daemon_perror(LOG_ERR, "calloc");
		status = -1;
		goto end;
	}

	/* Start SNMP subagent thread */
	if (!(threads[0] = thread_start("snmp_subagent", snmp_subagent_main, NULL))) {
		daemon_log(LOG_ERR, "Failed to start thread");
		status = -1;
		goto end;
	}

	/* Start NDB MGM monitor threads  */
	for(i=0; i<globals.num_clusters; i++) {
		char thread_name[30];
		snprintf(thread_name, sizeof(thread_name), "ndb_mgm#%d", i+1);
		if (!(threads[i+1] = thread_start(thread_name, ndb_mgm_main, &globals.clusters[i]))) {
			daemon_log(LOG_ERR, "Failed to start thread");
			status = -1;
			goto end;
		}
	}

	/* Wait for any threads to finish */
	while(globals.running) {
		for(i=0; i<2; i++) {
			if (!thread_running(threads[i])) {
				globals.running = 0;
				break;
			}
		}
		sleep(1000000);
	}

  end:
	/* Tell all threads to stop (doesn't wait for them to stop so shutdown is faster) */
	/* Then wait for threads to finish, check their exit status */
	for(i=0; i<num_threads; i++) {
		if (threads[i]) {
			thread_stop(threads[i]);
		}
	}
	for(i=0; i<num_threads; i++) {
		if (threads[i]) {
			if (thread_exit_status(threads[i]) < 0) status = -1;
			thread_destroy(threads[i]);
		}
	}
	free(threads);

	/* Other cleanup */
	for(i=0; i<globals.num_clusters; i++) {
		/* TODO free node tables */
		free(globals.clusters[i].info.name);
		free(globals.clusters[i].info.connectstring);
	}
	free(globals.clusters);

	/* Return the status */
	return status;
}

